/*
   DOES NOT USE THE BUILT-IN DETECTION FUNCTIONALITY!!

alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"WEB-CLIENT Microsoft Excel HFPicture record stack buffer overflow attempt"; flowbits:isset,file.xls; flow:to_client,established; content:"|66 08 00 00 00 00 00 00 00 00 00 00|"; content:"|66 08|"; distance:-16; within:2; metadata:policy security-ips drop, service http; reference:cve,2010-1248; reference:url,technet.microsoft.com/en-us/security/bulletin/MS10-038; classtype:attempted-user; sid:16649;)

 * Use at your own risk.
 *
 * Copyright (C) 2005-2008 Sourcefire, Inc.
 * 
 * This file is autogenerated via rules2c, by Brian Caswell <bmc@sourcefire.com>
 */


#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"
 
//#define DEBUG 1
#ifdef DEBUG
#define DEBUG_SO(code) code
#else
#define DEBUG_SO(code)
#endif

/* declare detection functions */
int rule16649eval(void *p);

/* declare rule data structures */
/* flowbits:isset "file.xls"; */
static FlowBitsInfo rule16649flowbits0 =
{
    "file.xls",
    FLOWBIT_ISSET,
    0,
};

static RuleOption rule16649option0 =
{
    OPTION_TYPE_FLOWBIT,
    {
        &rule16649flowbits0
    }
};
/* flow:established, to_client; */
static FlowFlags rule16649flow1 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule16649option1 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule16649flow1
    }
};
#ifndef CONTENT_FAST_PATTERN
#define CONTENT_FAST_PATTERN 0
#endif
// content:"f|08 00 00 00 00 00 00 00 00 00 00|", depth 0, fast_pattern; 
static ContentInfo rule16649content2 = 
{
    (uint8_t *) "f|08 00 00 00 00 00 00 00 00 00 00|", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_FAST_PATTERN|CONTENT_BUF_NORMALIZED|CONTENT_RELATIVE, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule16649option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule16649content2
    }
};
// content:"f|08|", offset -16, depth 2, relative; 
static ContentInfo rule16649content3 = 
{
    (uint8_t *) "f|08|", /* pattern (now in snort content format) */
    2, /* depth */
    -16, /* offset */
    CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule16649option3 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule16649content3
    }
};

/* references for sid 16649 */
/* reference: cve "2010-1248"; */
static RuleReference rule16649ref1 = 
{
    "cve", /* type */
    "2010-1248" /* value */
};

/* reference: url "technet.microsoft.com/en-us/security/bulletin/MS10-038"; */
static RuleReference rule16649ref2 = 
{
    "url", /* type */
    "technet.microsoft.com/en-us/security/bulletin/MS10-038" /* value */
};

static RuleReference *rule16649refs[] =
{
    &rule16649ref1,
    &rule16649ref2,
    NULL
};

/* metadata for sid 16649 */
/* metadata:service http, policy security-ips drop; */
static RuleMetaData rule16649service1 = 
{
    "service http"
};


//static RuleMetaData rule16649policy1 = 
//{
//    "policy security-ips drop"
//};

static RuleMetaData rule16649policy2 = 
{
    "policy max-detect-ips drop"
};

static RuleMetaData *rule16649metadata[] =
{
    &rule16649service1,
//    &rule16649policy1,
    &rule16649policy2,
    NULL
};

RuleOption *rule16649options[] =
{
    &rule16649option0,
    &rule16649option1,
    &rule16649option2,
    &rule16649option3,
    NULL
};

Rule rule16649 = {
   /* rule header, akin to => tcp any any -> any any */
   {
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
   
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
   
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       16649, /* sigid */
       10, /* revision */
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "FILE-OFFICE Microsoft Excel HFPicture record stack buffer overflow attempt",     /* message */
       rule16649refs /* ptr to references */
       ,rule16649metadata
   },
   rule16649options, /* ptr to rule options */
   &rule16649eval, /* DO NOT use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule16649eval(void *p) {
    const uint8_t *cursor_raw, *end_of_payload;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *cursor_detect;

    uint16_t record_size;
    uint32_t subrecord_size;
  
    uint16_t subrecord_recVerInstance;  // rh.recVer and rh.recInstance
    uint16_t subrecord_recType;  // rh.recType

    DEBUG_SO(printf("rule16649eval enter\n"));

    if(sp == NULL)
        return RULE_NOMATCH;

    // flowbits:isset "file.xls";
    if (processFlowbits(p, rule16649options[0]->option_u.flowBit) <= 0) 
        return RULE_NOMATCH;

    // flow:established, to_client;
    if (checkFlow(p, rule16649options[1]->option_u.flowFlags) <= 0) 
        return RULE_NOMATCH;

    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_raw, &end_of_payload) <= 0)
        return RULE_NOMATCH;

    // check HFPicture.frtHeader field's static values
    // content:"f|08 00 00 00 00 00 00 00 00 00 00|", offset 2, depth 12, relative, fast_pattern;
    while (contentMatch(p, rule16649options[2]->option_u.content, &cursor_raw) > 0)
    {
        cursor_detect = cursor_raw;
 
        // HFPicture's type = 0x866
        // content:"f|08|", offset -16, depth 2, relative;
        if (contentMatch(p, rule16649options[3]->option_u.content, &cursor_detect) > 0)
        {
            if (cursor_detect + 24 > end_of_payload)
                return RULE_NOMATCH;

	    record_size = read_little_16(cursor_detect);
            DEBUG_SO(printf("record size 0x%04x\n", record_size);)
            
            // if record size does not meet its minimum or maximum requirement, search for the next HFPicture record
            if (record_size < 22 || record_size >= 8224) 
                continue;

            cursor_detect += 16; // jump over header size (2), frtHeader (12), flags (1) and reserved (1) fields
            subrecord_recVerInstance = read_little_16(cursor_detect);

            if (subrecord_recVerInstance != 0x000F)
                continue;

            cursor_detect += 2; // jump over rgDrawing.header.recVer and rgDrawing.header.recInstance fields
            subrecord_recType = read_little_16(cursor_detect);
           
            if (subrecord_recType != 0xF000 && subrecord_recType != 0xF002)
                continue;

            cursor_detect += 2; // jump over rgDrawing.header.recType field
            subrecord_size = read_little_32(cursor_detect);
            DEBUG_SO(printf("subrecord size 0x%08x\n", subrecord_size);)

            // if the following condition is NOT satisfied, malicious
            // HFPicture.Length == sizeof(FrtHeader) [0xc] + sizeof(DataItem_UInt16) [0x2] + sizeof(OfficeArtRecordHeader) [0x8] + rh.recLen
            if (record_size != subrecord_size + 22) // if subrecord's data size + subrecord header (8 bytes) + !=  
                return RULE_MATCH;
        }
    }
   
    return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule16649,
    NULL
};
*/
